package com.wbihua.common.metrics.metric.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import com.wbihua.common.metrics.manager.MetricManager;
import com.wbihua.common.metrics.metric.EventMeterGauge;
import com.wbihua.common.metrics.type.EventGaugeType;
import io.micrometer.core.instrument.Gauge;

import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

public class EventGauge implements EventMeterGauge {
    private static final SafeConcurrentHashMap<List<String>, AtomicLong> POOL = new SafeConcurrentHashMap<>();
    private AtomicLong counter;

    private final EventGaugeType counterType;
    private MetricManager metricManager;

    public EventGauge(EventGaugeType counterType) {
        this.counterType = counterType;
    }
    public EventGauge(EventGaugeType counterType, MetricManager metricManager) {
        this(counterType);
        this.metricManager = metricManager;
    }
    @Override
    public void registry(MetricManager metricManager) {
        this.counter = metricManager.getMetricRegistry().gauge(getCounterType().getName(), metricManager.getTags(), new AtomicLong(0), AtomicLong::get);
    }

    @Override
    public <T> T getMeter() {
        return (T)this.counter;
    }

    @Override
    public <T> T getMeter(String... tagValues) {
        return (T)POOL.get(tagValues);
    }

    @Override
    public EventGaugeType getCounterType() {
        return this.counterType;
    }

    @Override
    public void increment(double count) {
        counter.addAndGet((long)count);
    }

    @Override
    public void increment(double count, String... labelValues) {
        getGaugeValue(labelValues).addAndGet((long)count);
    }

    @Override
    public void decrement(double count) {
        counter.addAndGet(-(long)count);
    }

    @Override
    public void decrement(double count, String... labelValues) {
        getGaugeValue(labelValues).addAndGet(-(long)count);
    }

    private AtomicLong getGaugeValue(String[] tagValues) {
        if (tagValues.length != counterType.getTags().length) {
            throw new IllegalArgumentException("Incorrect number of labels.");
        }
        for (String value: tagValues) {
            if (value == null) {
                throw new IllegalArgumentException("Label cannot be null.");
            }
        }
        return POOL.computeIfAbsent(ListUtil.toList(tagValues), values -> {
            AtomicLong gaugeValue = new AtomicLong(0);
            Gauge.Builder<AtomicLong> builder = Gauge.builder(counterType.getName(), gaugeValue, AtomicLong::doubleValue);
            builder.tags(metricManager.getTags());
            String[] tags = counterType.getTags();
            for (int i = 0; i < values.size(); i++) {
                builder.tag(tags[i], values.get(i));
            }
            builder.description(counterType.getDescription())
                    .baseUnit(counterType.getBaseUnit())
                    .register(metricManager.getMetricRegistry());
            return gaugeValue;
        });
    }

}
